package com.tianxiabuyi.model.pojo;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.Transient;

import com.alibaba.fastjson.annotation.JSONField;
import com.tianxiabuyi.Input;
import com.tianxiabuyi.Message;
import com.tianxiabuyi.model.base.TXBYObject;
import com.tianxiabuyi.persist.DBTools;
import com.tianxiabuyi.persist.QBuilder;
import com.tianxiabuyi.utils.Tools;

/**
 * 大部分API的访问如预约、查看预约记录都需要用户身份验证，Token类中提供了生成令牌，验证令牌，更新令牌等方法<br/>
 * 对于手机客户端应用，令牌默认有效时间为1小时，超过1小时后自动更新旧令牌，并返回请求的接口数据<br/>
 * 对于微信应用，如果不退出登录，令牌永久有效
 * @author yangh
 */
@Entity
@Table(name = "token")
public class Token extends TXBYObject {
	private Integer uid;             // 用户uid
	@Column(name="expire_in")@JSONField(name = "expire_in")
	private Integer expireIn;        // 令牌失效毫秒数，微信用户失效时间为－1
	private String userName;         // 用户名
	private String password;         // 密码
	private String token;            // 生成的令牌，如果是微信用户，令牌为openid
	@Transient
	private boolean wechat;          // 如果true，表示来自微信，失效时间为-1

	/**
	 * 创建一个手机客户端令牌对象，有效时间3600毫秒
	 */
	public Token() {
		this.expireIn = 1 * 60 * 60;
		this.wechat = false;
	}

	/**
	 * 用户uid
	 * @return 用户uid
	 */
	public Integer getUid() {
		return uid;
	}

	/**
	 * 设置用户uid
	 * @param uid 用户uid
	 */
	public void setUid(Integer uid) {
		this.uid = uid;
	}

	/**
	 * 令牌失效毫秒数<br/>
	 * 手机客户端默认3600毫秒<br/>
	 * 微信永久有效
	 * @return 令牌失效毫秒数
	 */
	public Integer getExpireIn() {
		return expireIn;
	}

	/**
	 * 设置令牌失效毫秒数
	 * @param expireIn 令牌失效毫秒数
	 */
	public void setExpireIn(Integer expireIn) {
		this.expireIn = expireIn;
	}

	/**
	 * 获取用户名
	 * @return 用户名
	 */
	public String getUserName() {
		return userName;
	}

	/**
	 * 设置用户名
	 * @param userName 用户名
	 */
	public void setUserName(String userName) {
		this.userName = userName;
	}

	/**
	 * 密码
	 * @return 密码
	 */
	public String getPassword() {
		return password;
	}

	/**
	 * 设置密码
	 * @param password 密码
	 */
	public void setPassword(String password) {
		this.password = password;
	}

	/**
	 * 令牌字符串
	 * @return 令牌
	 */
	public String getToken() {
		return token;
	}

	/**
	 * 设置令牌
	 * @param token 令牌
	 */
	public void setToken(String token) {
		this.token = token;
	}

	/**
	 * 是否微信用户
	 * @return 是否微信用户
	 */
	public boolean isWechat() {
		return wechat;
	}

	/**
	 * 设置令牌类型为微信用户
	 * @param wechat 是微信用户
	 */
	public void setWechat(boolean wechat) {
		this.wechat = wechat;
	}

	/**
	 * 生成Token对象保存到数据库，并且将所有属性和属性值放入Map中返回
	 * @return Token所有属性键值对
	 */
	@SuppressWarnings("rawtypes")
	public Map genToken() {
		HashMap<String, Object> map = (HashMap<String, Object>)Tools.toMap(this);
		boolean wechat = Tools.getBool(map.get("wechat") + "");
		map.remove("wechat");
		if (wechat) { // 微信
			String hql = "from token where hospital = '" + this.getHospital() + "' and token = '" + token + "'";
			List list = QBuilder.db("basedb").queryHql(hql);
			if (list.size() == 0) {
				map.put("expireIn", -1);
				DBTools.db("basedb").addItem("token", map);
			}
			return map;
		}

		// 手机客户端
		String token = Tools.getMD5(userName + map.get("cTime") + password);
		map.put("token", token);
		DBTools.db("basedb").addItem("token", map);
		return map;
	}

	/**
	 * 验证令牌<br>
	 * 如果验证通过返回状态码0，否则返回其它状态码<br>
	 * @param input 请求对象
	 * @return 令牌验证结果
	 */
	@SuppressWarnings("rawtypes")
	public static Message validateToken(Input input) {
		Message message = new Message();
//		Message message = input.validate();
//		int errCode = message.getErrcode();
//		if (0 != errCode ) { // input验证不通过
//			return message;
//		}

		String tokenString = input.getDesc("token", "");
		int hospital = input.getInt("hospital", 0);
		if (("".equals(tokenString)) || (0 == hospital)) {
			message.setErrcode(20001);
			return message;
		}

		// 数据库查询
		List list = QBuilder.db("basedb").queryHql("from token where hospital = '" + hospital + "' and token = '" + tokenString + "'");
		if (list.size() == 0) // 没有匹配的记录
		{
			message.setErrcode(20004);
			return message;
		}
		// 取出数据库中token记录
		Map tokenMap = (HashMap) list.get(0);
		int status = Tools.getInt(tokenMap.get("status") + "", 2); 
		if (status == 3) {
			message.setErrcode(20003);
			return message;
		}

		
		if (-1 == Tools.getInt(tokenMap.get("expireIn") + "", 0)) // 微信用户
		{
			message.setErrmsg("token验证成功");
			message.put("token", Token.fromMap(tokenMap, Token.class));
			return message;
		}

		// 延迟30秒，防止客户端没过期，传递到服务端过期了
		int expireIn = 1000 * (Tools.getInt(tokenMap.get("expireIn") + "", 0) + 20);
		Long createAt = Tools.getLong(tokenMap.get("cTime") + "", 0L);
		Long now = System.currentTimeMillis();
		if (now > (createAt + expireIn)) // 过期
		{
			message.setErrcode(20002);
			return message;
		}

		message.setErrmsg("token验证成功");
		message.put("token", Token.fromMap(tokenMap, Token.class));
		return message;
	}

	/**
	 * 更新令牌
	 * 如果更新成功返回状态码0，否则返回其它状态码<br>
	 * @param input 请求对象
	 * @param expiresIn 令牌有效时间毫秒数，如果为0则从input对象的map中取expiresIn
	 * @return 令牌更新结果描述
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static Message refreshToken(Input input,
			int expiresIn) {
		Message message = new Message();
//		Message message = input.validate();
//		int errCode = message.getErrcode();
//		if (0 != errCode) // input验证不通过
//		{
//			return message;
//		}

		String tokenString = input.getDesc("token", "");
		int hospital = input.getInt("hospital", 0);
		Map<String, String> map = new HashMap<String, String>();
		if (("".equals(tokenString)) || (0 == hospital)) {
			message.setErrcode(20001);
			return message;
		}

		// 数据库查询
		List list = QBuilder.db("basedb").queryHql("from token where hospital = '" + hospital + "' and token = '"+ tokenString + "'");
		if (list.size() == 0) // 没有匹配的记录
		{
			message.setErrcode(20004);
			return message;
		}
		// 取出数据库中token记录
		Map tokenMap = (HashMap) list.get(0);
		int status = Tools.getInt(tokenMap.get("status") + "", 2);  
		if (status == 3) {
			message.setErrcode(20003);
			return message;
		}

		// 修改创建时间
		Long now = System.currentTimeMillis();
		tokenMap.put("cTime", now);
		String userName = Tools.getDesc(tokenMap.get("userName") , "");
		String password = Tools.getDesc(tokenMap.get("password") , "");
		if (0 == expiresIn) {
			expiresIn = Tools.getInt(tokenMap.get("expireIn") + "");
		}
		String newTokenString = Tools.getMD5(userName + now + password);
		tokenMap.put("token", newTokenString);
		tokenMap.put("expireIn", expiresIn);
		
		DBTools.db("basedb").modItem("token", tokenMap);

		message.setErrmsg("token更新成功");
		message.put("token", newTokenString);
		message.put("expiresIn", expiresIn);
		return message;
	}

	/**
	 * 更新令牌
	 * 如果更新成功返回状态码0，否则返回其它状态码<br>
	 * @param input 请求对象
	 * @return 令牌更新结果描述
	 */
	public static Message refreshToken(Input input) {
		int expiresIn = 0;
		return refreshToken(input, expiresIn);
	}

	/**
	 * 删除令牌
	 * @param input 请求对象
	 * @return 删除结果描述 
	 */
	@SuppressWarnings("rawtypes")
	public static Message revokeToken(Input input) {
		Message message = new Message();
//		Message message = input.validate();
//		int errCode = message.getErrcode();
//		if (0 != errCode) // input验证不通过
//		{
//			return message;
//		}

		String tokenString = input.getDesc("token");
		int hospital = input.getInt("hospital", 0);
		Map<String, String> map = new HashMap<String, String>();
		if (("".equals(tokenString)) || (0 == hospital)) {
			message.setErrcode(20001);
			return message;
		}

		// 数据库查询
		List list = QBuilder.db("basedb").queryHql("from token where hospital = '" + hospital + "' and token = '" + tokenString + "'");
		if (list.size() == 0) { // 没有匹配的记录
			message.setErrcode(20004);
			return message;
		}
		// 取出数据库中token记录
		Map tokenMap = (HashMap) list.get(0);
		int status = Tools.getInt(tokenMap.get("status") + "", 2); 
		if (status == 3) {
			message.setErrcode(20003);
			return message;
		}

		// 删除
		QBuilder.db("basedb").execHQL("delete from token where hospital= '" + hospital + "' and token='" + tokenString + "'");
		message.setErrmsg("token已清除");
		return message;
	}
}